package org.pt.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.IService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.pt.dto.*;
import org.pt.components.Response;
import org.pt.exception.*;
import org.pt.mapper.InvitationMapper;
import org.pt.mapper.UserMapper;
import org.pt.mapper.UserPossessMapper;
import org.pt.model.Invitation;
import org.pt.model.User;
import org.pt.model.UserPossess;
import org.pt.utils.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IService<User> {

    private final MailServiceImpl mailService;

    @Value("${user.avatar.path}")
    private String avatarStoragePath;

    @Value("${user.avatar.default}")
    private String defaultAvatar;

    @Autowired
    private UserMapper userMapper;

    @Autowired
    private UserPossessMapper userPossessMapper;

    @Autowired
    private InvitationMapper invitationMapper;

    @Autowired
    private InvitationCodeUtil invitationCodeUtil;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Transactional(rollbackFor = Exception.class)
    public Response<String>register(RegisterDto registerDto, MultipartFile avatar) throws RegisterException, InvitationException, IOException {

        int userId= IdGenerator.nextId();

        String avatarPath = defaultAvatar;
        if (!avatar.isEmpty()) {
            if (!avatar.getContentType().startsWith("image/")) {
                throw new RegisterException("头像格式错误");
            }
            //TODO:处理传入的图片
            avatarPath = avatarStoragePath + userId+".jpg";
        }

        byte[] fileBytes = avatar.getBytes();
        // 写入文件
        Files.write(Paths.get(avatarPath), fileBytes);

        //1.验证验证码是否正确
        String vertificationCode=registerDto.getVertificationCode();
        String email=registerDto.getEmail();
        boolean passVerify=EmailCodeUtils.verifyCode(email,vertificationCode);
        if(!passVerify){throw new RegisterException("验证码无效");}

        //2.验证用户名是否存在
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, registerDto.getUsername());
        User user = userMapper.selectOne(queryWrapper);
        if(user!=null){throw new RegisterException("用户名已存在");}
        //3，验证邀请码是否存在
        InvitationDto invitationDto=invitationCodeUtil.validateInvitationCode(registerDto.getInvitationCode());

        //4.生成id,添加数据
        user=new User();
        user.setId(userId);
        user.setPassKey(PasskeyGenerator.getPasskey(userId));
        user.setUsername(registerDto.getUsername());
        user.setEmail(registerDto.getEmail());
        user.setPassword(DigestUtils.md5Hex(registerDto.getPassword()));
        user.setAge(registerDto.getAge());
        user.setBio(registerDto.getBio());
        user.setCollege(registerDto.getCollege());
        user.setSchool(registerDto.getSchool());
        user.setRegisterTime(new Date());
        user.setMagicValue(500);
        user.setIsBanned(false);
        user.setIsAdmin(false);
        user.setAvatarPath(avatarPath);
        userMapper.insert(user);

        //5.生成邀请记录，奖励邀请人
        int inviterId=invitationDto.getId();
        User inviter=userMapper.selectById(inviterId);
        int magicValue=inviter.getMagicValue();
        int newMagicValue=magicValue+ScoreUtil.getScore();
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", inviterId)
                .set("magic_value", newMagicValue)
                .setSql("invite_count=invite_count+1"); // 直接设置新值
        userMapper.update(updateWrapper);
        Invitation invitation=new Invitation();
        invitation.setInviterId(inviterId);
        invitation.setInviteeId(userId);
        invitation.setInviteTime(new Date());
        invitationMapper.insert(invitation);

        return Response.success("register success");
    }

    public Response<LoginResponseDto> login(LoginDto loginDto) throws LoginException {
        //验证验证码
        boolean passVerify=EmailCodeUtils.verifyCode(loginDto.getEmail(),loginDto.getVerificationCode());
        if(!passVerify){throw new LoginException("验证码无效");}

        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, loginDto.getUsername());
        User user = userMapper.selectOne(queryWrapper);
        if(user==null){throw new LoginException("用户不存在");}

        String password=user.getPassword();
        String email=user.getEmail();
        System.out.println(DigestUtils.md5Hex(loginDto.getPassword()));
        System.out.println(password);
        if(!password.equals(DigestUtils.md5Hex(loginDto.getPassword()))){throw new LoginException("密码不正确");}
        if(!email.equals(loginDto.getEmail())){throw new LoginException("邮箱与用户名不匹配");}

        //token内容
        var map=new LinkedHashMap<String,String>();
        map.put("id", String.valueOf(user.getId()));
        map.put("username", user.getUsername());
        map.put("email", user.getEmail());
        map.put("isAdmin", String.valueOf(user.getIsAdmin()));
        map.put("passKey",user.getPassKey());

        String token = JwtToken.create(map);

        LoginResponseDto loginResponseDto= new LoginResponseDto(
                user.getId(),
                user.getUsername(),
                user.getEmail(),
                user.getIsAdmin(),
                user.getAvatarPath(),
                token,
                user.getIsBanned()
        );

        //用redis存储token，实现唯一登录
        redisTemplate.opsForValue().set(
                "user:latest_token:" + user.getId(),
                token
        );
        redisTemplate.expire("user:latest_token:" + user.getUsername(), JwtToken.AMOUNT, TimeUnit.HOURS);

        map.put("token", token);

        return Response.success(loginResponseDto);
    }

    public Response<Map<String,String>> getVerifyCode(String username,String emailAdd,int isLogin) throws LoginException, RegisterException {

        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email",emailAdd);
        User user = userMapper.selectOne(queryWrapper);
        //如果是登陆的话需要验证邮箱是否存在,用户名和邮箱是否匹配
        System.out.println(isLogin);
        if(isLogin==1) {
            if(user==null) {throw new LoginException("没有该邮箱");}
            if(!user.getUsername().equals(username)) {throw new LoginException("邮箱和用户不匹配");}
        }
        else{
            //注册时邮箱不能存在
            if(user!=null){throw new RegisterException("邮箱已存在");}
        }

        String verifyCode = EmailCodeUtils.generateCode();
        EmailCodeUtils.saveCode(emailAdd,verifyCode);

        mailService.sendAsync(emailAdd,"您的验证码","您的验证码是：" + verifyCode + "，有效期为1分钟。");

        var map=new LinkedHashMap<String,String>();
        map.put("email", emailAdd);
        map.put("verifyCode", verifyCode);
        return Response.success(map);
    }

    public Response<InvitationDto> getInvitationCode(Integer inviterId,int remaining,Boolean isAdmin) throws InvitationException {

        InvitationDto invitationDto=invitationCodeUtil.generateInvitationCode(inviterId,isAdmin,remaining);
        return Response.success(invitationDto);

    }

    public Response<String> getUserPasskey(int userId) throws UserException {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, userId);
        User user = userMapper.selectOne(queryWrapper);
        if(user==null){throw new UserException("用户不存在");}
        return Response.success(user.getPassKey());
    }

    public Response<UserInfoDto> getUserInfo(int userId) throws  UserException {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, userId);
        User user = userMapper.selectOne(queryWrapper);
        if(user==null){throw new UserException("用户不存在");}

        LambdaQueryWrapper<UserPossess> possessQueryWrapper = new LambdaQueryWrapper<>();
        possessQueryWrapper.eq(UserPossess::getUserId, userId);

        // 获取与该用户相关的所有记录
        List<UserPossess> userPossessList = userPossessMapper.selectList(possessQueryWrapper);

        // 计算总的 uploaded 和 downloaded
        long totalUploaded = userPossessList.stream().mapToInt(UserPossess::getUploaded).sum();
        long totalDownloaded = userPossessList.stream().mapToInt(UserPossess::getDownloaded).sum();
        int plusMagicValue= (int) (totalUploaded/(totalDownloaded+1)/5000);

        // 更新用户的 uploaded 和 downloaded 字段
        user.setTotalUpload(totalUploaded);
        user.setTotalDownload(totalDownloaded);

        userMapper.updateById(user); // 更新用户信息

        UserInfoDto userinfo= new UserInfoDto(
                user.getUsername(),
                user.getEmail(),
                user.getRegisterTime(),
                user.getAvatarPath(),
                user.getBio(),
                user.getAge(),
                user.getSchool(),
                user.getCollege(),
                totalUploaded,
                totalDownloaded,
                user.getInviteCount(),
                plusMagicValue+user.getMagicValue(),
                user.getWorkCount()
        );
        return Response.success(userinfo);
    }

    public Response<List<String>>updateUserInfo(UpdateInfoDto updateInfoDto) throws UserException
    {
        List<String> updateList = new ArrayList<>();
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id",updateInfoDto.getId());
        updateInfoDto.getAge().ifPresent(age -> {updateList.add("age");updateWrapper.set("age",age);});
        updateInfoDto.getSchool().ifPresent(school -> {updateList.add("school");updateWrapper.set("school",school);});
        updateInfoDto.getCollege().ifPresent(college -> {updateList.add("college");updateWrapper.set("college",college);});
        updateInfoDto.getBio().ifPresent(bio -> {updateList.add("bio");updateWrapper.set("bio",bio);});

        userMapper.update(updateWrapper);

        return Response.success(updateList);
    }


}
